home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / elecmail / uupc11ys.zip / MAIL / ADDRESS.C next >
C/C++ Source or Header  |  1993-04-16  |  25KB  |  631 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    a d d r e s s . c                                               */
  3. /*                                                                    */
  4. /*    Address parsing routines for UUPC/extended                      */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <sys/types.h>
  12.  
  13. #include "lib.h"
  14. #include "hlib.h"
  15. #include "address.h"
  16. #include "hostable.h"
  17. #include "security.h"
  18.  
  19. /*--------------------------------------------------------------------*/
  20. /*                          Global variables                          */
  21. /*--------------------------------------------------------------------*/
  22.  
  23. currentfile();
  24.  
  25. /*--------------------------------------------------------------------*/
  26. /*                     Local function prototypes                      */
  27. /*--------------------------------------------------------------------*/
  28.  
  29. static char *rfc_route( char *tptr, char **nptr, char **pptr );
  30.  
  31. /*--------------------------------------------------------------------*/
  32. /*    u s e r _ a t _ n o d e                                         */
  33. /*                                                                    */
  34. /*    break a UUCP path or RFC-822 address into the basic user and    */
  35. /*    node components                                                 */
  36. /*                                                                    */
  37. /*    Note:    This routine assume an address of the form             */
  38. /*             path!node1!user@node2 is for a user@node1 routed via   */
  39. /*             node2 and then path.                                   */
  40. /*--------------------------------------------------------------------*/
  41.  
  42. void user_at_node(const char *raddress,
  43.                   char *hispath,
  44.                   char *hisnode,
  45.                   char *hisuser)
  46. {
  47.  
  48.    static char *saveaddr = NULL;
  49.    static char *savepath;
  50.    static char *savenode;
  51.    static char *saveuser;
  52.  
  53.    char *uptr;                      /* Pointer to his user id              */
  54.    char *nptr;                      /* Pointer to his node id              */
  55.    char *pptr;                      /* Pointer to next node in path to him */
  56.    char *tptr;                      /* Temporary token pointer             */
  57.    char *wptr;                      /* Work pointer (not used between
  58.                                        steps                               */
  59.    char *address;
  60.  
  61.    struct HostTable *Hptr = NULL;   /* Pointer to host name table          */
  62.  
  63.  
  64.    if ( strlen( raddress ) >= MAXADDR )
  65.    {
  66.       printmsg(0,"Unable to process %d length address: %s",
  67.             strlen(raddress) , raddress );
  68.       panic();
  69.    }
  70.  
  71. /*--------------------------------------------------------------------*/
  72. /*                     Determine if local address                     */
  73. /*--------------------------------------------------------------------*/
  74.  
  75.    if (!strpbrk(raddress,"!@"))     /* Any host delimiters?                */
  76.    {                                /* No --> report local data            */
  77.       strcpy(hisuser,raddress);
  78.       strcpy(hisnode,E_nodename);
  79.       strcpy(hispath,E_nodename);
  80.       strcpy(hisuser,raddress);
  81.       printmsg(5,"user_at_node: Address '%s' is local",raddress);
  82.       return;
  83.    }
  84.  
  85. /*--------------------------------------------------------------------*/
  86. /*    If the current address is the same as the last processed remote */
  87. /*    address, then return the same information as what we determined */
  88. /*    last time.                                                      */
  89. /*--------------------------------------------------------------------*/
  90.  
  91.    if ((saveaddr != NULL) && equal(raddress,saveaddr))
  92.    {
  93.       strcpy(hispath,savepath);
  94.       strcpy(hisnode,savenode);
  95.       strcpy(hisuser,saveuser);
  96.       return;
  97.    }
  98.  
  99. /*--------------------------------------------------------------------*/
  100. /*   The address is different; save the new address and then proceed  */
  101. /*   to parse it.                                                     */
  102. /*--------------------------------------------------------------------*/
  103.  
  104.    address = strdup(raddress);   /* Copy address for parsing         */
  105.    checkref(address);            /* Verify allocation worked         */
  106.  
  107.    if (saveaddr != NULL)         /* Was the data previously allocated?  */
  108.    {                             /* Yes --> Free it                     */
  109.       free(saveaddr);
  110.    }
  111.  
  112.    saveaddr = strdup(address);   /* Remember address for next pass   */
  113.  
  114.    nptr = nil(char);             /* No known node for user           */
  115.    pptr = E_mailserv;            /* Default routing via mail server  */
  116.    tptr = address;               /* Remember start of address        */
  117.  
  118. /*--------------------------------------------------------------------*/
  119. /*  The address may be RFC-822 syntax; attempt to parse that format   */
  120. /*--------------------------------------------------------------------*/
  121.  
  122.    uptr = tptr = rfc_route( tptr, &nptr, &pptr );
  123.  
  124. /*--------------------------------------------------------------------*/
  125. /*   If the user had an RFC-822 path, then the pointer to the path is */
  126. /*   now initialized, and the remainder of the path has been dropped  */
  127. /*   from *tptr; otherwise, the entire address is found via *tptr     */
  128. /*--------------------------------------------------------------------*/
  129.  
  130.    wptr  = strrchr(tptr,'@');  /* Get last at sign, since it's right
  131.                                   to left scan (more or less)         */
  132.  
  133. /*--------------------------------------------------------------------*/
  134. /*    Translation of following:  If the at-sign (@) is not the        */
  135. /*    first character and the character preceding the at-sign is      */
  136. /*    not a bang (!), then break the address down into user and       */
  137. /*    node.                                                           */
  138. /*--------------------------------------------------------------------*/
  139.  
  140.    if (( wptr > tptr ) && ( strchr("!:",*(wptr-1)) == NULL))
  141.    {
  142.       uptr  = tptr;               /* Get user part of userid @node    */
  143.       *wptr++ = '\0';             /* Terminate user portion           */
  144.       tptr  = wptr;               /* Get node part of userid @node    */
  145.    }
  146.  
  147.    if (tptr != NULL)           /* Did we get a node?                  */
  148.    {                           /* Yes --> Save it                     */
  149.       nptr = tptr;
  150.       pptr = HostPath( nptr, pptr);
  151.    } /* if */
  152.  
  153. /*--------------------------------------------------------------------*/
  154. /*   Now, we will try stripping off any uucp path that the address    */
  155. /*   may have acquired; we'll assume the last node is the addressee's */
  156. /*   node.                                                            */
  157. /*--------------------------------------------------------------------*/
  158.  
  159.    uptr = strtok(uptr,"!");
  160.    tptr = strtok(NULL,"");
  161.  
  162.    while ( tptr != NULL )
  163.    {
  164.       nptr = uptr;                  /* First token is node           */
  165.       if (*tptr == '@')             /* Explicit RFC-822 route?       */
  166.       {                             /* Yes --> Examine in detail     */
  167.          uptr = strtok( rfc_route( tptr, &nptr, &pptr ), "!");
  168.                                     /* Second token, or what's
  169.                                        left of it, is user id        */
  170.          tptr = strtok(NULL,"");    /* Save rest of string           */
  171.       } /* if (*tptr == '@') */
  172.       else {
  173.          uptr = strtok(tptr,"!");   /* Second token is user id       */
  174.          tptr = strtok(NULL,"");    /* Save rest of string           */
  175.          pptr = HostPath( nptr, pptr);
  176.       } /* else */
  177.    } /* while */
  178.  
  179. /*--------------------------------------------------------------------*/
  180. /*   Finally, we parse off any internet mail that used the infamous % */
  181. /*   hack (user%node1@gatewayb)                                       */
  182. /*--------------------------------------------------------------------*/
  183.  
  184.    while ((tptr = strrchr(uptr,'%')) != NULL)   /* Get last percent  */
  185.    {
  186.       *tptr = '@';               /* Make it an RFC-822 address       */
  187.       uptr  = strtok(uptr,"@");  /* Get user part of userid @node    */
  188.       nptr  = strtok(NULL,"@");  /* Get node part of userid @node    */
  189.       pptr  = HostPath(nptr, pptr); /* Old node is new path          */
  190.    } /* while */
  191.  
  192. /*--------------------------------------------------------------------*/
  193. /*   If the last known hop in the path is via our own system, but the */
  194. /*   target node is not our own system, route the message via our     */
  195. /*   default mail server.                                             */
  196. /*--------------------------------------------------------------------*/
  197.  
  198.    nptr = HostAlias( nptr );
  199.    if (equali(pptr,E_nodename))
  200.                               /* Is mail routed via our local system? */
  201.    {                          /* Yes --> Determine if destined for us */
  202.       Hptr = checkname(nptr);          /* Locate the system       */
  203.       if (Hptr == BADHOST)             /* System known?           */
  204.       {                                /* No --> Route default    */
  205.          printmsg(5,
  206.             "user_at_node: Routing mail for \"%s\" via default mail server",
  207.                   nptr);
  208.          pptr = E_mailserv;
  209.       } /* if */
  210.       else
  211.          nptr = E_nodename;   /* Must be local delivery              */
  212.    }  /* if */
  213.  
  214. /*--------------------------------------------------------------------*/
  215. /*                         Print our results                          */
  216. /*--------------------------------------------------------------------*/
  217.  
  218.    printmsg(9,
  219.          "user_at_node: Address \"%s\" is \"%s\" at \"%s\" via \"%s\"",
  220.             raddress, uptr, nptr, pptr);
  221.  
  222. /*--------------------------------------------------------------------*/
  223. /*  We have parsed the address.  Fill in the information for caller   */
  224. /*--------------------------------------------------------------------*/
  225.  
  226.    strcpy(hispath,pptr);
  227.    strcpy(hisnode,nptr);
  228.    strcpy(hisuser,uptr);
  229.  
  230. /*--------------------------------------------------------------------*/
  231. /*   Save the parsed information along with the original address we   */
  232. /*   were passed in.  This could save breaking it down again.         */
  233. /*--------------------------------------------------------------------*/
  234.  
  235.    savepath = newstr(hispath);
  236.    savenode = newstr(hisnode);
  237.    saveuser = newstr(hisuser);
  238.  
  239.    free(address);
  240. }  /* user_at_node */
  241.  
  242. /*--------------------------------------------------------------------*/
  243. /*    r f c _ r o u t e                                               */
  244. /*                                                                    */
  245. /*    Strip off explicit RFC-822 routing from an address              */
  246. /*--------------------------------------------------------------------*/
  247.  
  248. static char *rfc_route( char *tptr, char **nptr, char **pptr )
  249. {
  250.  
  251. /*--------------------------------------------------------------------*/
  252. /*          Loop as long as we have an explicit RFC-822 path          */
  253. /*--------------------------------------------------------------------*/
  254.  
  255.    while (*tptr == '@')        /* Explicit RFC 822 path?             */
  256.    {
  257.       *nptr = strtok(++tptr,",:");  /* First token is path/node      */
  258.       tptr = strtok(NULL,""); /* Second has rest, including user id  */
  259.       *pptr = HostPath( *nptr , *pptr );
  260.                               /* Determine actual path               */
  261.       printmsg(9,"rfc_route: RFC-822 explicit path: "
  262.                   "\"%s\" routed via \"%s\" is via \"%s\"",
  263.          tptr, *nptr, *pptr);
  264.    } /* while */
  265.  
  266. /*--------------------------------------------------------------------*/
  267. /*    At this point, *nptr is last node in list, *pptr is path to     */
  268. /*    *nptr, and *tptr is the rest of the string (userid?)            */
  269. /*--------------------------------------------------------------------*/
  270.  
  271.    return tptr;
  272. } /* rfc_route */
  273.  
  274. /*--------------------------------------------------------------------*/
  275. /*    H o s t A l i a s                                               */
  276. /*                                                                    */
  277. /*    Resolve a host alias to its real canonized name                 */
  278. /*--------------------------------------------------------------------*/
  279.  
  280. char *HostAlias( char *input)
  281. {
  282.    struct HostTable *hostp;
  283.  
  284.    hostp = checkname(input);
  285.  
  286. /*--------------------------------------------------------------------*/
  287. /*     If nothing else to look at, return original data to caller     */
  288. /*--------------------------------------------------------------------*/
  289.  
  290.    if (hostp == BADHOST)
  291.       return input;
  292.  
  293.    if ( hostp->hostname[0] == '*') /* Ignore wildcards     */
  294.       return input;
  295.  
  296. /*--------------------------------------------------------------------*/
  297. /*      If we already chased this chain, return result to caller      */
  298. /*--------------------------------------------------------------------*/
  299.  
  300.    if (hostp->aliased)
  301.    {
  302.       if ( hostp->realname  == NULL )
  303.       {
  304.          printmsg(0,"Alias table loop detected with host %s",
  305.                hostp->hostname);
  306.       }
  307.  
  308.       return hostp->realname;
  309.    } /* if */
  310.  
  311.    hostp->aliased = TRUE;        /* Prevent limitless recursion      */
  312.  
  313. /*--------------------------------------------------------------------*/
  314. /*                  Determine next host in the chain                  */
  315. /*--------------------------------------------------------------------*/
  316.  
  317.    if ( hostp->realname == NULL)  /* End of the line?        */
  318.       hostp->realname = hostp->hostname;
  319.    else
  320.       hostp->realname = HostAlias(hostp->realname);
  321.  
  322. /*--------------------------------------------------------------------*/
  323. /*                        Announce our results                        */
  324. /*--------------------------------------------------------------------*/
  325.  
  326.    printmsg( 5 ,
  327.             "HostAlias: \"%s\" is alias of \"%s\"",input,hostp->realname);
  328.  
  329.    return hostp->realname;
  330.  
  331. } /* HostAlias */
  332.  
  333. /*--------------------------------------------------------------------*/
  334. /*    H o s t P a t h                                                 */
  335. /*                                                                    */
  336. /*    Determine the path to a host                                    */
  337. /*--------------------------------------------------------------------*/
  338.  
  339. char *HostPath( char *input, char *best)
  340. {
  341.    struct HostTable *hostp;
  342.  
  343.    hostp = checkname( input );
  344.  
  345. /*--------------------------------------------------------------------*/
  346. /*     If nothing else to look at, return original data to caller     */
  347. /*--------------------------------------------------------------------*/
  348.  
  349.    if (hostp == BADHOST)
  350.       return best;
  351.  
  352.    if (hostp->hstatus == gatewayed)  /* Gatewayed?                    */
  353.       return hostp->hostname;      /* Yes --> Use name for path       */
  354.  
  355. /*--------------------------------------------------------------------*/
  356. /*      If we already chased this chain, return result to caller      */
  357. /*--------------------------------------------------------------------*/
  358.  
  359.    if (hostp->routed)
  360.    {
  361.       if ( hostp->via == NULL )
  362.       {
  363.          printmsg(0,"Routing table loop discovered at host %s",
  364.                      hostp->hostname);
  365.          panic();
  366.       }
  367.  
  368.       return hostp->via;
  369.    }
  370.  
  371.    hostp->routed  = TRUE;        /* Prevent limitless recursion      */
  372.  
  373. /*--------------------------------------------------------------------*/
  374. /*                  Determine next host in the chain                  */
  375. /*--------------------------------------------------------------------*/
  376.  
  377.    if ( hostp->via == NULL )
  378.    {
  379.       char *alias = HostAlias( hostp->hostname );
  380.  
  381.       if (equal(hostp->hostname,alias))
  382.       {
  383.          if (hostp->hstatus == localhost) /* Ourself?                */
  384.             hostp->via = E_nodename;      /* Yes --> Deliver local   */
  385.          else if ( checkreal( hostp->hostname ) == BADHOST )
  386.                                           /* Unknown system?         */
  387.             hostp->via = best;            /* Yes --> Use default     */
  388.          else
  389.             hostp->via = hostp->hostname; /* Known --> route to it   */
  390.       } /* if ( hostp->via == NULL ) */
  391.       else
  392.          hostp->via = HostPath( alias, best);
  393.    } /* if ( hostp->via == NULL ) */
  394.  
  395.    hostp->via = HostPath( hostp->hostname, hostp->via );
  396.  
  397.    printmsg( 5 ,"HostPath: \"%s\" routed via \"%s\"", input, hostp->via);
  398.  
  399.    return hostp->via;
  400.  
  401. } /* HostPath */
  402.  
  403. /*--------------------------------------------------------------------*/
  404. /*    E x t r a c t A d d r e s s                                     */
  405. /*                                                                    */
  406. /*    Returns the user name (if available and requested or            */
  407. /*    E-mail address of the user                                      */
  408. /*                                                                    */
  409. /*    Written by ahd 15 July 1989                                     */
  410. /*--------------------------------------------------------------------*/
  411.  
  412. char *ExtractAddress(char *result,
  413.                     const char *input ,
  414.                     FULLNAME fullname)
  415. {
  416.    char *nonblank = NULL;
  417.    char *column  = (char *) input;
  418.    char name[BUFSIZ];      /* User full name             */
  419.    char *nameptr = name;
  420.    char addr[BUFSIZ];      /* User e-mail address        */
  421.    char *addrptr  = addr;
  422.  
  423.    char state = 'A';                /* State = skip whitespace    */
  424.    char newstate = 'A';             /* Next state to process      */
  425.    int bananas = 0;                 /* No () being processed now  */
  426.    int len;
  427.    boolean quoted = FALSE;
  428.  
  429. /*--------------------------------------------------------------------*/
  430. /*   Begin loop to copy the input field into the address and or the   */
  431. /*   user name.  We will begin by copying both (ignoring whitespace   */
  432. /*   for addresses) because we won't know if the input field is an    */
  433. /*   address or a name until we hit either a special character of     */
  434. /*   some sort.                                                       */
  435. /*--------------------------------------------------------------------*/
  436.  
  437.    while ((*column != '\0') && (state != ','))
  438.    {
  439.       switch (state) {
  440.          case 'A':
  441.             if (isspace(*column))   /* Found first non-blank? */
  442.                break;               /* No --> keep looking    */
  443.             nonblank = column;
  444.             state = 'B';
  445.                                     /* ... and fall through          */
  446.          case 'B':
  447.          case ')':
  448.             newstate = *column;
  449.             switch(*column) {
  450.                case '(':
  451.                   bananas++;
  452.                   break;
  453.  
  454.                case '"':
  455.                   break;
  456.  
  457.                case '<':
  458.                   addrptr = addr;   /* Start address over      */
  459.                   nameptr = name;   /* Start name over again   */
  460.                   column  = nonblank - 1;
  461.                                     /* Re-scan in new state    */
  462.                   newstate = '>';   /* Proc all-non <> as name */
  463.                   break;            /* Begin addr over again   */
  464.                case ',':
  465.                   break;            /* Terminates address      */
  466.                case '>':
  467.                case ')':
  468.                   printmsg(0,"Invalid RFC-822 address: %s",nonblank);
  469.                   panic();          /* Ooops, funky address    */
  470.                   break;
  471.  
  472.                default:
  473.                   newstate = state; /* stay in this state            */
  474.                   if (!isspace(*column))
  475.                      *(addrptr++) = *column;
  476.             }  /* switch(*column) */
  477.             break;
  478.  
  479.          case '<':   if (*column == '>')
  480.                         newstate = '>';
  481.                      else if (!isspace(*column))
  482.                         *(addrptr++) = *column;
  483.                      break;
  484.  
  485.          case '>':   if (*column == '<')
  486.                         newstate = '<';
  487.                      else switch( *column )
  488.                      {
  489.                         case ')':
  490.                            if (quoted)
  491.                               *(nameptr++) = *column;
  492.                            else
  493.                               bananas--;
  494.                            break;
  495.  
  496.                         case '(':
  497.                            if (quoted)
  498.                               *(nameptr++) = *column;
  499.                            else
  500.                               bananas++;
  501.                            break;
  502.  
  503.                         case '"':
  504.                            if (bananas == 0)
  505.                            {
  506.                               quoted = !quoted;
  507.                               break;
  508.                            }
  509.                            /* else fall through */
  510.  
  511.                         default:
  512.                            *(nameptr++) = *column;
  513.                      } /* switch */
  514.                      break;
  515.  
  516.          case '(':   if (*column == '(')
  517.                         ++bananas;
  518.                      else if (*column == ')')
  519.                      {
  520.                         if (--bananas == 0)
  521.                         {
  522.                            newstate = ')';
  523.                            break;
  524.                         }
  525.                      }
  526.                      else
  527.                         *(nameptr++) = *column;
  528.                      break;
  529.  
  530.          case '"':   if (*column == '"')
  531.                         newstate = ')';
  532.                      else
  533.                         *(nameptr++) = *column;
  534.  
  535.                      break;
  536.  
  537.          default:    panic();
  538.                                  /* Logic error, bad state        */
  539.                      break;
  540.  
  541.       }  /* switch (state) */
  542.       state = newstate;
  543.       column++;
  544.    } /* while */
  545.  
  546.  
  547. /*--------------------------------------------------------------------*/
  548. /*                   Verify we retrieved an address                   */
  549. /*--------------------------------------------------------------------*/
  550.  
  551.    if (state == 'A')
  552.    {
  553.       printmsg(0, "ExtractAddress: Could not find address in \"%s\"",
  554.                column);
  555.       panic();
  556.    }
  557.  
  558. /*--------------------------------------------------------------------*/
  559. /*                 Fill in the results for the caller                 */
  560. /*--------------------------------------------------------------------*/
  561.  
  562.    *addrptr = '\0';
  563.    *nameptr = '\0';
  564.    *result  = '\0';
  565.    len = strlen( addr );
  566.  
  567.    if ((fullname == ADDRESSONLY) ||
  568.        ((fullname == FULLADDRESS) && (state == 'B')))
  569.    {
  570.       if ( len >= MAXADDR )
  571.       {
  572.          printmsg(0,"ExtractAddress: Address exceeds %d characters: %s",
  573.                      MAXADDR, addr );
  574.          panic();
  575.       }
  576.       strcpy(result,addr);         /* Return the full address    */
  577.    }
  578.    else if (state != 'B')
  579.    {
  580.       while (--nameptr >= name)
  581.       {
  582.          if (isspace(*nameptr))
  583.             *nameptr = '\0';
  584.          else
  585.             break;
  586.       }
  587.  
  588. /*--------------------------------------------------------------------*/
  589. /*               Strip leading blanks from the address                */
  590. /*--------------------------------------------------------------------*/
  591.  
  592.       nameptr = name;
  593.       while (isspace(*nameptr))
  594.          nameptr++;
  595.  
  596.       if ( strlen( nameptr ) >= MAXADDR )
  597.       {
  598.          printmsg(0,"ExtractAddress: Truncating name %s" , nameptr);
  599.          nameptr[ MAXADDR - 1 ] = '\0';
  600.       }
  601.  
  602.       if ( fullname == FULLADDRESS )
  603.       {
  604.          if ( len >= (MAXADDR-6) )
  605.          {
  606.             printmsg(0,"ExtractAddress: Address exceeds %d characters: %s",
  607.                         MAXADDR-6, addr );
  608.             panic();
  609.          }
  610.          nameptr[ MAXADDR - len - 6] = '\0';
  611.          sprintf( result , "\"%s\" <%s>", nameptr, addr );
  612.       }
  613.       else
  614.          strncpy(result,nameptr, MAXADDR);
  615.  
  616.    } /* else */
  617.  
  618.    printmsg(4,"ExtractAddress: %s into <%s> \"%s\"",
  619.             nonblank,addr,(fullname) ? result : name);
  620.  
  621. /*--------------------------------------------------------------------*/
  622. /*   Return the position of the next address, if any, to the caller   */
  623. /*--------------------------------------------------------------------*/
  624.  
  625.    if ( *column == '\0')
  626.       return NULL;
  627.    else
  628.       return column + 1;
  629.  
  630. } /*ExtractAddress*/
  631.